package com.yunfeng.common.util;

import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.PrintSetup;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * 
 */
public class FileUtils {
	public static Logger log = LoggerFactory.getLogger(FileUtils.class);

	public final static long ONE_KB = 1024;
	public final static long ONE_MB = ONE_KB * 1024;
	public final static long ONE_GB = ONE_MB * 1024;
	public final static long ONE_TB = ONE_GB * (long) 1024;
	public final static long ONE_PB = ONE_TB * (long) 1024;

	/**
	 * 
	 * 得到文件大小。
	 * 
	 * @param fileSize
	 * @return
	 */
	public static String getHumanReadableFileSize(long fileSize) {
		if (fileSize < 0) {
			return String.valueOf(fileSize);
		}
		String result = getHumanReadableFileSize(fileSize, ONE_PB, "PB");
		if (result != null) {
			return result;
		}

		result = getHumanReadableFileSize(fileSize, ONE_TB, "TB");
		if (result != null) {
			return result;
		}
		result = getHumanReadableFileSize(fileSize, ONE_GB, "GB");
		if (result != null) {
			return result;
		}
		result = getHumanReadableFileSize(fileSize, ONE_MB, "MB");
		if (result != null) {
			return result;
		}
		result = getHumanReadableFileSize(fileSize, ONE_KB, "KB");
		if (result != null) {
			return result;
		}
		return String.valueOf(fileSize) + "B";
	}

	private static String getHumanReadableFileSize(long fileSize, long unit,
			String unitName) {
		if (fileSize == 0)
			return "0";

		if (fileSize / unit >= 1) {
			double value = fileSize / (double) unit;
			DecimalFormat df = new DecimalFormat("######.##" + unitName);
			return df.format(value);
		}
		return null;
	}

	public static String getFileExt(String fileName) {
		if (fileName == null)
			return "";

		String ext = "";
		int lastIndex = fileName.lastIndexOf(".");
		if (lastIndex >= 0) {
			ext = fileName.substring(lastIndex + 1).toLowerCase();
		}

		return ext;
	}

	/**
	 * 得到不包含后缀的文件名字。
	 * 
	 * @return
	 */
	public static String getRealName(String name) {
		if (name == null) {
			return "";
		}

		int endIndex = name.lastIndexOf(".");
		if (endIndex == -1) {
			return null;
		}
		return name.substring(0, endIndex);
	}

	private static SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM");

	public static CellStyle createHeadStyle(Workbook wb) {
		CellStyle style;
		Font headerFont = wb.createFont();
		headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_CENTER);
		style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE
				.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		style.setFont(headerFont);
		return style;
	}

	public static void exportExcel(HttpServletResponse response, List<?> list)
			throws Exception {

		if (list.isEmpty()) {
			return;
		}

		// 定义输出流，以便打开保存对话框______________________begin
		OutputStream os = response.getOutputStream();// 取得输出流
		response.reset();// 清空输出流
		response.setHeader("Content-disposition",
				"attachment; filename=temp.xls");
		// 设定输出文件头
		response.setContentType("application/msexcel");// 定义输出类型
		// 定义输出流，以便打开保存对话框_______________________end
		Workbook wb = new HSSFWorkbook();
		Sheet sheet = wb.createSheet("new sheet");
		Object temp = list.get(0);
		Field[] fields = temp.getClass().getDeclaredFields();
		Row headerRow = sheet.createRow(0);
		CellStyle headStyle = createHeadStyle(wb);
		for (int i = 0; i < fields.length; i++) {
			Cell cell = headerRow.createCell(i);
			cell.setCellValue(fields[i].getName());
			cell.setCellStyle(headStyle);
		}
		int rownum = 1;
		CellStyle cellStyle = wb.createCellStyle();
		for (Iterator<?> it = list.iterator(); it.hasNext();) {
			Object entity = it.next();
			Row row = sheet.createRow(rownum++);
			for (int i = 0; i < fields.length; i++) {
				Cell cell = row.createCell(i);
				Field field = fields[i];
				field.setAccessible(true);
				cell.setCellValue(String.valueOf(field.get(entity)));
				cell.setCellStyle(cellStyle);
			}
		}
		wb.write(os);
		os.close();
	}

	public static void exportExcel(String[][] data, String[] titles)
			throws Exception {
		Workbook wb = new HSSFWorkbook();
		Map<String, CellStyle> styles = createStyles(wb);
		Sheet sheet = wb.createSheet("Business Plan");
		// turn off gridlines
		sheet.setDisplayGridlines(false);
		sheet.setPrintGridlines(false);
		sheet.setFitToPage(true);
		sheet.setHorizontallyCenter(true);
		PrintSetup printSetup = sheet.getPrintSetup();
		printSetup.setLandscape(true);
		// the following three statements are required only for HSSF
		sheet.setAutobreaks(true);
		printSetup.setFitHeight((short) 1);
		printSetup.setFitWidth((short) 1);

		// the header row: centered text in 48pt font
		Row headerRow = sheet.createRow(0);
		headerRow.setHeightInPoints(12.75f);
		for (int i = 0; i < titles.length; i++) {
			Cell cell = headerRow.createCell(i);
			cell.setCellValue(titles[i]);
			cell.setCellStyle(styles.get("header"));
		}
		// columns for 11 weeks starting from 9-Jul
		Calendar calendar = Calendar.getInstance();
		int year = calendar.get(Calendar.YEAR);

		// calendar.setTime(fmt.parse("9"));
		calendar.set(Calendar.YEAR, year);
		for (int i = 0; i < 11; i++) {
			Cell cell = headerRow.createCell(titles.length + i);
			cell.setCellValue(calendar);
			cell.setCellStyle(styles.get("header_date"));
			calendar.roll(Calendar.WEEK_OF_YEAR, true);
		}
		// freeze the first row
		sheet.createFreezePane(0, 1);

		Row row;
		Cell cell;
		int rownum = 1;
		for (int i = 0; i < data.length; i++, rownum++) {
			row = sheet.createRow(rownum);
			if (data[i] == null)
				continue;

			for (int j = 0; j < data[i].length; j++) {
				cell = row.createCell(j);
				String styleName;
				boolean isHeader = i == 0 || data[i - 1] == null;
				switch (j) {
				case 0:
					if (isHeader) {
						styleName = "cell_b";
						cell.setCellValue(Double.parseDouble(data[i][j]));
					} else {
						styleName = "cell_normal";
						cell.setCellValue(data[i][j]);
					}
					break;
				case 1:
					if (isHeader) {
						styleName = i == 0 ? "cell_h" : "cell_bb";
					} else {
						styleName = "cell_indented";
					}
					cell.setCellValue(data[i][j]);
					break;
				case 2:
					styleName = isHeader ? "cell_b" : "cell_normal";
					cell.setCellValue(data[i][j]);
					break;
				case 3:
					styleName = isHeader ? "cell_b_centered"
							: "cell_normal_centered";
					cell.setCellValue(Integer.parseInt(data[i][j]));
					break;
				case 4: {
					calendar.setTime(fmt.parse(data[i][j]));
					calendar.set(Calendar.YEAR, year);
					cell.setCellValue(calendar);
					styleName = isHeader ? "cell_b_date" : "cell_normal_date";
					break;
				}
				case 5: {
					int r = rownum + 1;
					String fmla = "IF(AND(D" + r + ",E" + r + "),E" + r + "+D"
							+ r + ",\"\")";
					cell.setCellFormula(fmla);
					styleName = isHeader ? "cell_bg" : "cell_g";
					break;
				}
				default:
					styleName = data[i][j] != null ? "cell_blue"
							: "cell_normal";
				}

				cell.setCellStyle(styles.get(styleName));
			}
		}

		// group rows for each phase, row numbers are 0-based
		sheet.groupRow(4, 6);
		sheet.groupRow(9, 13);
		sheet.groupRow(16, 18);

		// set column widths, the width is measured in units of 1/256th of a
		// character width
		sheet.setColumnWidth(0, 256 * 6);
		sheet.setColumnWidth(1, 256 * 33);
		sheet.setColumnWidth(2, 256 * 20);
		sheet.setZoom(3, 4);

		// Write the output to a file
		String file = "businessplan.xls";
		FileOutputStream out = new FileOutputStream(file);
		wb.write(out);
		out.close();
	}

	/**
	 * create a library of cell styles
	 */
	private static Map<String, CellStyle> createStyles(Workbook wb) {
		Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
		DataFormat df = wb.createDataFormat();

		CellStyle style;
		Font headerFont = wb.createFont();
		headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_CENTER);
		style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE
				.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		style.setFont(headerFont);
		styles.put("header", style);

		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_CENTER);
		style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE
				.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		style.setFont(headerFont);
		style.setDataFormat(df.getFormat("d-mmm"));
		styles.put("header_date", style);

		Font font1 = wb.createFont();
		font1.setBoldweight(Font.BOLDWEIGHT_BOLD);
		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_LEFT);
		style.setFont(font1);
		styles.put("cell_b", style);

		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_CENTER);
		style.setFont(font1);
		styles.put("cell_b_centered", style);

		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_RIGHT);
		style.setFont(font1);
		style.setDataFormat(df.getFormat("d-mmm"));
		styles.put("cell_b_date", style);

		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_RIGHT);
		style.setFont(font1);
		style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		style.setDataFormat(df.getFormat("d-mmm"));
		styles.put("cell_g", style);

		Font font2 = wb.createFont();
		font2.setColor(IndexedColors.BLUE.getIndex());
		font2.setBoldweight(Font.BOLDWEIGHT_BOLD);
		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_LEFT);
		style.setFont(font2);
		styles.put("cell_bb", style);

		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_RIGHT);
		style.setFont(font1);
		style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		style.setDataFormat(df.getFormat("d-mmm"));
		styles.put("cell_bg", style);

		Font font3 = wb.createFont();
		font3.setFontHeightInPoints((short) 14);
		font3.setColor(IndexedColors.DARK_BLUE.getIndex());
		font3.setBoldweight(Font.BOLDWEIGHT_BOLD);
		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_LEFT);
		style.setFont(font3);
		style.setWrapText(true);
		styles.put("cell_h", style);

		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_LEFT);
		style.setWrapText(true);
		styles.put("cell_normal", style);

		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_CENTER);
		style.setWrapText(true);
		styles.put("cell_normal_centered", style);

		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_RIGHT);
		style.setWrapText(true);
		style.setDataFormat(df.getFormat("d-mmm"));
		styles.put("cell_normal_date", style);

		style = createBorderedStyle(wb);
		style.setAlignment(CellStyle.ALIGN_LEFT);
		style.setIndention((short) 1);
		style.setWrapText(true);
		styles.put("cell_indented", style);

		style = createBorderedStyle(wb);
		style.setFillForegroundColor(IndexedColors.BLUE.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		styles.put("cell_blue", style);

		return styles;
	}

	private static CellStyle createBorderedStyle(Workbook wb) {
		CellStyle style = wb.createCellStyle();
		style.setBorderRight(CellStyle.BORDER_THIN);
		style.setRightBorderColor(IndexedColors.BLACK.getIndex());
		style.setBorderBottom(CellStyle.BORDER_THIN);
		style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
		style.setBorderLeft(CellStyle.BORDER_THIN);
		style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
		style.setBorderTop(CellStyle.BORDER_THIN);
		style.setTopBorderColor(IndexedColors.BLACK.getIndex());
		return style;
	}
}
